﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using Keepo.Models;
using System.Runtime.InteropServices;
using Infrastructure.Data;

namespace Keepo.Helpers
{
    public class ImageHelper
    {

        public static void CreateThumbnails(List<DesignImage> images)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                foreach (DesignImage image in images)
                {
                    try
                    {
                        CreateThumbnailAndLowRes(image);
                    }
                    catch { }
                }
            }
        }

        public static void CreateThumbnailAndLowRes(DesignImage image)
        {
            if (string.IsNullOrEmpty(image.ThumbnailUrl))
            {
                image.ThumbnailUrl = GenerateThumbnailFileName(image.URL);

                // Create Thumbnail ?
                var thumbnailPath = HttpContext.Current.Server.MapPath("~/") + image.ThumbnailUrl;
                if (!File.Exists(thumbnailPath))
                {
                    CreateThumbnail(image.URL, image.ThumbnailUrl, 150);
                }

                var imagePath = HttpContext.Current.Server.MapPath("~/") + image.URL;

                if (File.Exists(imagePath))
                {
                    //save the dimensions of this image
                    using (FileStream fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
                    {
                        using (Image imageFile = Image.FromStream(fs))
                        {
                            image.ImageWidth = imageFile.Width;
                            image.ImageHeight = imageFile.Height;
                        }
                    }

                    int lowResSize = 500;
                    if(Math.Max(image.ImageWidth, image.ImageHeight) > lowResSize)
                    {
                        image.LowResUrl = GenerateLowResFileName(image.URL);
                        
                        // Create Low Res ?
                        var lowResPath = HttpContext.Current.Server.MapPath("~/") + image.LowResUrl;
                        if (!File.Exists(lowResPath))
                        {
                            CreateThumbnail(image.URL, image.LowResUrl, lowResSize);
                        }
                    }
                }
            }
        }

        public static string GenerateFilenameCommon(string filename, string exp)
        {
            var extensionIndex = filename.LastIndexOf('.');
            return filename.Substring(0, extensionIndex) + exp + filename.Substring(extensionIndex, filename.Length - extensionIndex);
        }

        public static string GenerateThumbnailFileName(string filename)
        {
            return GenerateFilenameCommon(filename, "-thumb");
        }

        public static string GenerateCroppedFileName(string filename)
        {
            return GenerateFilenameCommon(filename, "-cropped");
        }

        public static string GenerateLowResFileName(string filename)
        {
            return GenerateFilenameCommon(filename, "-lowRes");
        }

        public static Bitmap CreateThumbnail(string imageFileName, string thumbnailFileName, int maxSize = 300, int quality = 90)
        {
            Image srcImage;
            try
            {
                string fullSrcname = HttpContext.Current.Server.MapPath("~/") + imageFileName;
                srcImage = Image.FromFile(fullSrcname);
            }
            catch
            {
                return null;
            }

            float s1 = (float)maxSize / srcImage.Width;
            float s2 = (float)maxSize / srcImage.Height;

            float s = Math.Min(s1, s2);

            int thumbnailWidth = Convert.ToInt32(s * srcImage.Width);
            int thumbnailHeight = Convert.ToInt32(s * srcImage.Height);

            Bitmap dstImage = new Bitmap(thumbnailWidth, thumbnailHeight);
            Graphics g = Graphics.FromImage((Image)dstImage);

            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            g.DrawImage(srcImage, 0, 0, thumbnailWidth, thumbnailHeight);
            g.Dispose();

            string fullDstName = HttpContext.Current.Server.MapPath("~/") + thumbnailFileName;

            try
            {
                // Encoder parameter for image quality 
                EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, quality);
                ImageCodecInfo imageCodec = GetEncoderInfo("image/jpeg");

                var extension = Path.GetExtension(imageFileName).ToUpper();
                if (extension == ".JPG" || extension == ".JPEG")
                {
                    // Jpeg image codec 
                    imageCodec = GetEncoderInfo("image/jpeg");
                }
                else if (extension == ".PNG")
                {
                    // png image codec 
                    imageCodec = GetEncoderInfo("image/png");
                }

                EncoderParameters encoderParams = new EncoderParameters(1);
                encoderParams.Param[0] = qualityParam;

                dstImage.Save(fullDstName, imageCodec, encoderParams);
            }
            catch
            {
                return null;
            }

            return dstImage;
        }

        public static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
            // Get image codecs for all image formats 
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

            // Find the correct image codec 
            for (int i = 0; i < codecs.Length; i++)
                if (codecs[i].MimeType == mimeType)
                    return codecs[i];
            return null;
        }

        public static void TrimBitmap(string srcFileName, string dstFileName)
        {
            string fullSrcName = HttpContext.Current.Server.MapPath("~/") + srcFileName;
            string fullDstName = HttpContext.Current.Server.MapPath("~/") + dstFileName;

            Bitmap src = new Bitmap(Bitmap.FromFile(fullSrcName));
            Bitmap dst = TrimBitmap(src);

            dst.Save(fullDstName);
        }

        public static Rectangle NonTransparentBounds(String filename)
        {
            string fullname = HttpContext.Current.Server.MapPath("~/") + filename;
            Bitmap bitmap = new Bitmap(Bitmap.FromFile(fullname));

            return NonTransparentBounds(bitmap);
        }

        public static Keepo.Models.Services.Rect NonTransparentBoundsExport(String filename)
        {
            Keepo.Models.Services.Rect result = new Keepo.Models.Services.Rect();

            Rectangle rect = NonTransparentBounds(filename);
            result.OffsetX = rect.X;
            result.OffsetY = rect.Y;
            result.Width = rect.Width;
            result.Height = rect.Height;

            return result;
        }

        public static Rectangle NonTransparentBounds(Bitmap source)
        {
            Rectangle rect = default(Rectangle);
            BitmapData data = null;
            try
            {
                data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                byte[] buffer = new byte[data.Height * data.Stride];
                Marshal.Copy(data.Scan0, buffer, 0, buffer.Length);
                int xMin = int.MaxValue;
                int xMax = 0;
                int yMin = int.MaxValue;
                int yMax = 0;
                for (int y = 0; y < data.Height; y++)
                {
                    for (int x = 0; x < data.Width; x++)
                    {
                        byte alpha = buffer[y * data.Stride + 4 * x + 3];
                        if (alpha != 0)
                        {
                            if (x < xMin) xMin = x;
                            if (x > xMax) xMax = x;
                            if (y < yMin) yMin = y;
                            if (y > yMax) yMax = y;
                        }
                    }
                }
                if (xMax < xMin || yMax < yMin)
                {
                    // Image is empty...
                    return rect;
                }
                rect = Rectangle.FromLTRB(xMin, yMin, xMax + 1, yMax + 1);
            }
            finally
            {
                if (data != null)
                    source.UnlockBits(data);
            }

            return rect;
        }

        /// <summary>
        /// Trim the specified Bitmap by removing all the Transparent areas
        /// </summary>
        public static Bitmap TrimBitmap(Bitmap source)
        {
            Rectangle srcRect = NonTransparentBounds(source);

            if (srcRect.IsEmpty)
            {
                return null;
            }

            Bitmap dest = new Bitmap(srcRect.Width, srcRect.Height);

            Rectangle destRect = new Rectangle(0, 0, srcRect.Width, srcRect.Height);
            using (Graphics graphics = Graphics.FromImage(dest))
            {
                graphics.DrawImage(source, destRect, srcRect, GraphicsUnit.Pixel);
            }
            return dest;
        }

        static public int calcLowResSize(DesignImage image)
        {
            var imagePath = HttpContext.Current.Server.MapPath("~/") + image.URL;

            FileInfo fileInfo = new FileInfo(imagePath);
            const int MAX_IMAGE_SIZE = 204800;

            //check if the image size is bigger than 200KB
            if (fileInfo.Length > MAX_IMAGE_SIZE)
            {
                //scale down this image for it to be less than 200KB in size
                var scalingRatio = ((double)MAX_IMAGE_SIZE) / fileInfo.Length;
                scalingRatio = Math.Sqrt(scalingRatio);
                var maxSize = Convert.ToInt32(Math.Max(image.ImageWidth, image.ImageHeight) * scalingRatio);
                return maxSize;
            }

            return -1;
        }

        static public long addDesignImage(DesignImage image)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                image.CookieGuid = CookieGuidAttribute.getGuid();
                var imagePath = HttpContext.Current.Server.MapPath("~/") + image.URL;

                if (UserHelper.IsLogon())
                {
                    image.UserId = UserHelper.CurrentUser().UserId;
                }

                // Image already contains width and height
                CreateThumbnailAndLowRes(image);

                //add to db
                repository.Add<DesignImage>(image);
                repository.UnitOfWork.SaveChanges();

                return image.DesignImageId;
            }
        }

        /// <summary>
        /// this function get name of image file and resize the image to a small size
        /// then it saves the small image to the disk
        /// </summary>
        /*public static Bitmap CreateThumbnail(string image_filename, string newImageFile)
        {
            //Reading the images in
            System.Drawing.Image myimage;
            try
            {
                myimage = System.Drawing.Image.FromFile(image_filename);
            }
            catch
            {
                //Response.Write("Couldn't open file" + image_filename + "<br>");
                return null;
            }

            //Creating the thumbnail bitmap
            int thumb_width = myimage.Width;
            int thumb_height = myimage.Height;
            int topOffset = 0;
            int leftOffset = 0;

            //define the sizes of the new small image - according to the original sizes
            //resize it so that width and height will be 500 pixels
            if (myimage.Width > myimage.Height && myimage.Width > 500)
            {
                //if the width is bigger - make the height 500, and the width small in proportion
                thumb_height = 500;
                float small_width = float.Parse(myimage.Width.ToString()) / (float.Parse(myimage.Height.ToString()) / 500);
                thumb_width = Convert.ToInt32(small_width);

                leftOffset = (thumb_width - 500) / 2;
            }
            else if (myimage.Height > myimage.Width && myimage.Height > 500)
            {
                //if the height is bigger - make the width 500, and the height small in proportion
                thumb_width = 500;
                float small_height = float.Parse(myimage.Height.ToString()) / (float.Parse(myimage.Width.ToString()) / 500);
                thumb_height = Convert.ToInt32(small_height);

                topOffset = (thumb_height - 500) / 2;
            }
            else if (myimage.Height == myimage.Width && myimage.Height > 500)
            {
                //if the height and width are even
                thumb_height = 500;
                thumb_width = 500;
            }

            Bitmap source_bitmap = new Bitmap(myimage);
            Bitmap thumb_bitmap = new Bitmap(500, 500);
            Graphics g = Graphics.FromImage(thumb_bitmap);
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            g.FillRectangle(Brushes.White, 0, 0, 500, 500);
            g.DrawImage(source_bitmap, -leftOffset, -topOffset, thumb_width, thumb_height);

            //Saving the thumbnail to disk
            ImageCodecInfo[] Info = ImageCodecInfo.GetImageEncoders();
            EncoderParameters Params = new EncoderParameters(1);
            Params.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
            thumb_bitmap.Save(newImageFile, Info[1], Params);

            return thumb_bitmap;
        }*/
    }
}